/*
 * Connection.java   0.0.1    28/set/2009
 * 
 * Copyright (c) 2009 mentalsmash.org
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * The use of the Apache License does not indicate that this project is
 * affiliated with the Apache Software Foundation.
 */
package org.mentalsmash.tazio.net.cs.client;

import java.io.IOException;
import java.io.Serializable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * This is the interface that clients should use to send messages to a
 * RemoteServer. A concrete instance of this interface abstracts a connection to
 * a server, and <strong>does not</strong> manage possible disconnections, or
 * server switching.
 * <p>
 * Basically it provides two patterns of use:
 * <ol>
 * <li>
 * A <strong>synchronous</strong> interaction: use
 * {@link #sendRequest(Serializable)} to send a message to the server and wait
 * for its response</li>
 * <li>
 * An <strong>asynchronous</strong> interaction: use
 * {@link #sendRequestAsync(Serializable)} to send a message to the server and
 * continue. The response can be retrievet at any time by polling the returned
 * {@link Future} object.</li>
 * </ol>
 * </p>
 * 
 * @author Andrea Reale <andrea.reale@gmail.com
 * @version 0.0.1
 * @see RemoteServer
 */
public interface Connection {
    
    /**
     * The default number of milliseconds a connection will timeout in.
     * <p>
     * A value of zero means no timeout (default is 0 )
     * </p>
     */
    final static int TIMEOUT_DEFAULT = 0; // the default timeout 30

    /**
     * Send an asynchronous request message to the server, and do
     * <strong>not</strong> wait for the response.
     * <p>
     * The response can later be retrieved using the {@link Future} reference
     * returned as the outcome of this methods
     * </p>
     * <p>
     * Notice that if any exception is thrown while asynchronously executing
     * this method you will not be notified, until you invoke
     * {@link Future#get()} on the returned object. At this time - If any
     * exception occurred - you will receive an {@link ExecutionException},
     * having as <code>cause</code> the original exception.
     * </p>
     * 
     * @param request
     *            any serializable object representing a request for the server
     * @return a {@link Future} handle that can be used to poll the response
     *         once it is available
     * @throws ConnectionStateException
     *             if this method is called while this connection is not valid
     * @see #isValid()
     */
    Future<Serializable> sendRequestAsync(Serializable request)
	    throws IOException, ConnectionStateExeption;

    /**
     * Send a synchronous request message to the server. The thread that calls
     * this method will block until a response (in the form of a serializable
     * object) is returned from the server.
     * <p>
     * The thread that invokes this method will perform itself the actual
     * writing and reading from the underlying connection
     * </p>
     * 
     * @param request
     *            any serializable object representing a request for the server
     * @return the response from the server, as a serializable object
     * @throws IOException
     *             if problems with the underlying communication mechanism (e.g.
     *             sockets) occur
     * @throws ConnectionStateException
     *             if this method is called while this connection is not valid
     * @see #isValid()
     */
    Serializable sendRequest(Serializable request) throws IOException,
	    ConnectionStateExeption;

    /**
     * Send a message to the server. Use this method if no response is expected
     * for the message sent.
     * <p>
     * This method is executed asynchronously hence the method returns
     * immediately without waiting for message to be sent. Nevertheless the
     * dispatching of the message can fail, and an exception may be thrown for
     * the thread that is actually sending the message. You can check whether
     * this method threw an exception or not by calling {@link Future#get()} on
     * the returned future instance: <br/>
     * If any exception occurred while sending the message an
     * {@link ExecutionException} will be rose at this point, bearing as its
     * cause the originial exception. <br />
     * Otherwise {@link Future#get()} should return {@link RequestStatus#OK}.
     * </p>
     * 
     * @param message
     *            the message to be sent
     * @return an instance of {@link Future} to check the outcome of this method
     * @throws ConnectionStateExeption
     *             if this method is called while this connection is not valid
     */
    Future<RequestStatus> sendMessageAsync(Serializable message)
	    throws ConnectionStateExeption;

    /**
     * Send a message to the server. Use this method if no response is expected
     * for the message sent.
     * <p>
     * This is the synchronous version of
     * {@link #sendMessageAsync(Serializable)}. <br/>
     * </p>
     * <p>
     * The thread that invokes this method will perform itself the actual
     * writing and reading from the underlying connection
     * </p>
     * 
     * @param message
     *            the message to be sent
     * @throws IOException
     *             if an I/O error occurs.
     * @throws ConnectionStateExeption
     *             if this method is called while this connection is not valid
     */
    void sendMessage(Serializable message) throws IOException,
	    ConnectionStateExeption;

    /**
     * Get the {@link RemoteServer} instance associated with this
     * <tt>Connection</tt> or <code>null</code> if currently not connected.
     * 
     * @return the {@link RemoteServer} instance associated with this
     *         <tt>Connection</tt>
     */
    RemoteServer getRemoteServer();

    /**
     * Checks whether this connection instance is still valid. I.E. it checks if
     * it is associated with a valid {@link RemoteServer} that is in the
     * <i>Connected State</i>
     * 
     * @return true if this connection instance is valid.
     * @see RemoteServer
     */
    boolean isValid();

    /**
     * Closes the connection and its related resources.
     * <p>
     * This method also cleans the status in the related {@link RemoteServer}
     * instance.
     * </p>
     */
    void close();

    enum RequestStatus {
	OK, EXCEPTION_OCCURRED;
    }

    /**
     * Sets the timeout for messages that require a response.
     * <p>
     * When calling such methods, if the timeout expires before receiving a
     * response a TimeOutException is thrown
     * </p>
     * 
     * @param millis
     *            the number of millisicends fot the timeout to be set. A
     *            timeout of zero means infinite timeout.
     * @throws ConnectionStateExeption
     * @throws IOException
     */
    void setTimeOut(int millis) throws ConnectionStateExeption, IOException;

    /**
     * Get the timeout associated to this connections.
     * <p>
     * This timeout is meaningful for messages that require a response.<br/>
     * When calling such methods, if the timeout expires before receiving a
     * response a TimeOutException is thrown
     * </p>
     * 
     * @return the timeout expressed in milliseconds
     * @throws IOException
     * @throws ConnectionStateExeption
     */
    int getTimeOut() throws ConnectionStateExeption, IOException;
    

}
